//
//  main.cpp
//  shared_ptr_study
//
//  Created by huge on 2021/7/23.
//  Copyright © 2021 huge. All rights reserved.
//

/*
 *https://blog.csdn.net/fengbingchun/article/details/52202007
 shared_ptr study link
*/

//#include "shared_ptr.hpp"
#include <iostream>
#include <memory> // shared_ptr
#include <thread>
#include <chrono>
#include <mutex>
#include <algorithm>


struct Base
{
    Base() { std::cout << "  Base::Base()\n"; }
    // Note: non-virtual destructor is OK here
    ~Base() { std::cout << "  Base::~Base()\n"; }
};

struct Derived:Base
{
    Derived() { std::cout << "  Derived::Derived()\n"; }
    ~Derived() { std::cout << "  Derived::~Derived()\n"; }

};

void thr(std::shared_ptr<Base> p)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
//    std::cout << "p.count: " << p.use_count() << "\n";
    std::shared_ptr<Base> lp = p; // thread-safe, even though the shared use_count is incremented
    {
        static std::mutex io_mutex;
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << "local pointer in a thread:\n"
                    << " lp.get()" << lp.get()
        <<" , lp.use_count() = " <<lp.use_count() << "\n";
    }
}

int test_shared_ptr1(){
    
    std::shared_ptr<Base> p = std::make_shared<Derived>();
    
    std::cout << "Created a shared Derived (as a pointer to Base)\n"
    << "  p.get() = " << p.get()
    << ", p.use_count() = " << p.use_count() << '\n';
    
    std::thread t1(thr,p),t2(thr,p),t3(thr,p);
    p.reset();
    
    std::cout << "Shared ownership between 3 threads and released\n"
    << "ownership from main:\n"
    << "  p.get() = " << p.get()
    << ", p.use_count() = " << p.use_count() << '\n';
    
    t1.join();t2.join();t3.join();
    std::cout << "All threads completed, the last one deleted Derived\n";

    return 0;
}

int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    
//    std::shared_ptr<Base> pB(new Base());
//    std::cout << " pB.usedcount: " << pB.use_count() << " pB.get()" << pB.get() << "\n";
//    thr(pB);
//    std::cout << " pB.usedcount: " << pB.use_count() << " pB.get()" << pB.get() << "\n";
    test_shared_ptr1();
    
    return 0;
}
